package com.yinxing.webapi.code.service.sys;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yinxing.framework.mybatis.TemplateService;
import com.yinxing.webapi.code.entity.sys.SysMenu;
import com.yinxing.webapi.code.mapper.sys.SysMenuMapper;
import com.yinxing.webapi.code.viewobje.sys.MenuTreeNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class SysMenuService extends TemplateService<SysMenu> {

    @Autowired
    private ISysRolemenuService sysRolemenuService;

    private SysMenuMapper getMapper() {
        return (SysMenuMapper) baseMapper;
    }

    /**
     * 查询全部菜单列表树(包括禁用状态)
     * @return (List转为树结构)
     */
    public List<MenuTreeNode> selectMenuTreeList() {
        List<SysMenu> menuList = this.selectAllList();
        List<MenuTreeNode> treeNodeList = sysMenuToTreeNode(menuList);
        return convertToTreeList(treeNodeList);
    }

    /**
     * 查询用户角色绑定的菜单树
     * @param sysUserId 用户ID
     */
    public List<MenuTreeNode> selectUserMenuTreeList(long sysUserId) {
        List<SysMenu> menuList = this.getMapper().selectUserMenuTreeList(sysUserId);
        List<MenuTreeNode> treeNodeList = sysMenuToTreeNode(menuList);
        return convertToTreeList(treeNodeList);
    }

    /**
     * 查询全部菜单列表树(包括禁用状态)
     * 把角色绑定过的菜单设置为选中状态
     * @param sysRoleId 角色ID
     * @return (List转为树结构)
     */
    public List<MenuTreeNode> selectRoleMenuTreeList(long sysRoleId) {
        List<SysMenu> menuList = this.selectAllList();
        //查询角色绑定的菜单集合
        Set<Long> menuIds = sysRolemenuService.selectMenuIdsByRoleId(sysRoleId);
        List<MenuTreeNode> treeNodeList = sysMenuToTreeNode(menuList);

        //把角色绑定过的菜单设置为选中状态(checked=true)
        treeNodeList.forEach(node -> {
            if (menuIds.contains(node.getId())) {
                //与角色与菜单已绑定
                node.setChecked(true);
            } else {
                //角色与菜单未绑定
                node.setChecked(false);
            }
            node.setExpanded(true);
            node.setExpandedEdit(true);
        });

        //转换为树结构体
        return convertToTreeList(treeNodeList);
    }

    /**
     * 查询全局菜单数据集合
     */
    public List<SysMenu> selectAllList() {
        List<SysMenu> menuList = baseMapper.selectList(new QueryWrapper<>());
        return menuList;
    }

    /**
     * 把SysMenu转换为MenuTreeNode类型(因为ExtJS需要固定数据格式)
     * @param menuList 菜单集合
     * @return MenuTreeNode 集合
     */
    public List<MenuTreeNode> sysMenuToTreeNode(List<SysMenu> menuList) {
        return menuList.stream().map(menu -> {
            MenuTreeNode node = new MenuTreeNode();
            node.setId(menu.getId_());
            node.setText(menu.getName_());
            node.setIndex(menu.getIndex_());
            node.setParentId(menu.getParentId_());
            node.setIconCls(menu.getIconCls_());
            node.setRowCls(menu.getRowCls_());
            node.setLeaf(menu.getLeaf_());
            node.setExpanded(menu.getExpanded_());
            node.setExpandedEdit(menu.getExpanded_());
            node.setQtip(menu.getQtip_());
            node.setChecked(null);
            node.setViewType(menu.getViewType_());
            node.setStop(menu.getStop_());
            return node;
        }).collect(Collectors.toList());
    }

    /**
     * 把list转为树结构
     * @param nodeList 菜单数据集合
     */
    public List<MenuTreeNode> convertToTreeList(List<MenuTreeNode> nodeList) {
        //树的根节点集合
        List<MenuTreeNode> rootList = new ArrayList<>();

        //先把数据全部放入map  key=Id value=对象
        Map<Long, MenuTreeNode> entityMap = new HashMap<>(128);
        for (MenuTreeNode node : nodeList) {
            entityMap.put(node.getId(), node);
        }

        for (MenuTreeNode node : nodeList) {
            MenuTreeNode parentEntity = entityMap.get(node.getParentId());
            // 在查询node的父节点,如果为null说明node就是根节点
            if (parentEntity == null) {
                // 将根节点加入到rootList中
                if(node.getParentId() == 0) {
                    rootList.add(node);
                }
                continue;
            }
            //把node加入到父节点的孩子中
            parentEntity.getChildren().add(node);
        }

        return rootList;
    }

    /**
     * 批量新增或修改菜单数据
     * @param records ExtJs提交的数据集合
     */
    public void insertOrUpdateBatch(List<MenuTreeNode> records) {
        for (MenuTreeNode record : records) {
            SysMenu menu = baseMapper.selectById(record.getId());
            if (menu != null) {
                copyValue(menu, record);
                baseMapper.updateById(menu);
            } else {
                menu = new SysMenu();
                copyValue(menu, record);
                baseMapper.insert(menu);
            }
        }
    }

    /**
     * 拷贝属性
     * @param menu 菜单数据
     * @param node ExtJs提交的数据
     */
    private void copyValue(SysMenu menu, MenuTreeNode node) {
        menu.setId_(node.getId());
        menu.setParentId_(node.getParentId());
        menu.setLeaf_(node.isLeaf());
        menu.setName_(node.getText());
        menu.setViewType_(node.getViewType());
        menu.setIndex_(node.getIndex());
        menu.setIconCls_(node.getIconCls());
        menu.setRowCls_(node.getRowCls());
        menu.setQtip_(node.getQtip());
        menu.setStop_(node.isStop());
        menu.setExpanded_(node.isExpandedEdit());
    }

    /**
     * 批量删除菜单(同时删除角色菜单数据)
     * @param records ExtJs提交的数据集合
     */
    public void deleteBatch(List<MenuTreeNode> records) {
        for (MenuTreeNode record : records) {
            baseMapper.deleteById(record.getId());
            //删除菜单下绑定的角色数据
            sysRolemenuService.deleteByMenuId(record.getId());
        }
    }

    /**
     * 启用|禁用
     * @param id 菜单ID
     */
    public void stopById(long id) {
        SysMenu menu = baseMapper.selectById(id);
        if (menu != null) {
            menu.setStop_(!menu.getStop_());
            this.updateById(menu);
        }
    }

    /**
     * 批量更新角色绑定菜单
     * @param sysRoleId 角色ID
     * @param records   绑定|解绑 的菜单数据集合
     */
    public void updateRoleMenuBindInfo(Long sysRoleId, List<MenuTreeNode> records) {
        for (MenuTreeNode node : records) {
            if (node.getChecked() != null) {
                if(node.getChecked()) {
                    sysRolemenuService.bindRoleMenu(sysRoleId, node.getId());
                }else {
                    sysRolemenuService.unbindRoleMenu(sysRoleId, node.getId());
                }
            }
        }
    }
}
